package com.feiyuan.movie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.feiyuan.common.utils.CommonUtils;
import com.feiyuan.common.utils.Constant;
import com.feiyuan.common.utils.HttpClientUtils;
import com.feiyuan.movie.entity.MovieJiListEntity;
import com.feiyuan.movie.entity.MovieListEntity;
import com.feiyuan.movie.entity.MovieUserHistoryEntity;
import com.feiyuan.movie.service.MovieJiListService;
import com.feiyuan.movie.service.MovieListService;
import com.feiyuan.movie.service.MovieUserHistoryService;
import com.feiyuan.movie.service.Search80SMovieService;
import com.feiyuan.movie.vo.*;
import com.feiyuan.movie.webmagic.eightens.PlayMovieUrlProcessor;
import com.feiyuan.movie.webmagic.eightens.Search80SMovieProcessor;
import com.feiyuan.movie.webmagic.eightens.SearchMovieDetailProcessor;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.selector.Html;

import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
public class Search80SMovieServiceImpl implements Search80SMovieService {

    private final Logger logger = LoggerFactory.getLogger(Search80SMovieServiceImpl.class);

    @Autowired
    private MovieListService movieListService;

    @Autowired
    private MovieJiListService jiListService;

    @Autowired
    private MovieUserHistoryService userHistoryService;

    @Override
    public Map<String, Object> search(String param) {
        Map<String, Object> map = new HashMap<>();

        String url = Constant.MOVIE_80S_BASE_URL + "/movie/search/";
        Map<String, String> params = new HashMap<>();
        params.put("search_typeid", "1");
        params.put("skey", param);
        params.put("Input", "搜索");
        String htmlText = HttpClientUtils.doPost(url, params, null);
        Html html = new Html(htmlText);
        // 图片地址
        List<String> imgList = html.xpath("//ul[@class='me1 clearfix']//li//a//img/@_src").all();
        // 影片网络地址
        List<String> movieHrefList = html.xpath("//ul[@class='me1 clearfix']//li/a/@href").all();
        // 影片名字
        List<String> movieNameList = html.xpath("//ul[@class='me1 clearfix']//li/a/@title").all();
        // 更新到第几集
        List<String> updateList = html.xpath("//ul[@class='me1 clearfix']//li//span[@class='tip']/text()").all();
        logger.info("\n======================================\n" +
                "imgList====>>>>{}\n" +
                "movieHrefList====>>>>{}\n" +
                "movieNameList====>>>>{}\n" +
                "updateList====>>>>{}\n" +
                "======================================", imgList, movieHrefList, movieNameList, updateList);
        List<Search80SMovieVO> movieVOS = new ArrayList<>();
        for (int i=0;i<imgList.size();i++) {
            Search80SMovieVO movieVO = new Search80SMovieVO();
            movieVO.setImgHref(imgList.get(i));
            movieVO.setMovieHref(movieHrefList.get(i));
            movieVO.setMovieName(movieNameList.get(i));
            movieVO.setMovieUpdate(updateList.get(i));
            movieVOS.add(movieVO);
        }
        map.put("code", 200);
        map.put("list", movieVOS);

        return map;
    }

    @Override
    public Map<String, Object> searchJi(Long userId, Search80SMovieVO movieVO) {
        Map<String, Object> map = new HashMap<>();
        if (movieVO == null) {
            map.put("code", 500);
            map.put("msg", "movie is null!");
            return map;
        }

        // 通过视频详细地址，查询相关集数数据
        String movieDetailUrl = Constant.MOVIE_80S_BASE_URL + movieVO.getMovieHref();
        // 同步查询
        Spider spider = Spider.create(new Search80SMovieProcessor(movieDetailUrl));
        ResultItems result = spider.get(movieDetailUrl);
        if (result != null) {
            List<Movie80SJiShuVO> movie80SJiShuVOS = result.get("list");
            map.put("code", 200);
            map.put("jiList", movie80SJiShuVOS);
            // 另起一个线程保存数据
            // 推荐使用Guava的ThreadFactory构建ThreadFactory，自定义线程名称 方便后续排查问题
            ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("mythread-pool-").build();
            ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(// 核心线程数，即2个常开窗口
                    2,
                    // 最大的线程数，银行所有的窗口
                    5,
                    // 空闲时间
                    5,
                    TimeUnit.SECONDS,
                    // 工作队列
                    new LinkedBlockingQueue<>(5),
                    // 线程工厂
                    threadFactory,
                    // 拒绝策略
                    new ThreadPoolExecutor.AbortPolicy());
            poolExecutor.execute(() -> {
                saveMovie(userId, movieVO, movie80SJiShuVOS);
            });
            return map;
        } else {
            logger.warn("result is null!");
        }
        return map;
    }

    @Override
    public Map<String, Object> startPlay(String collectionHref) {
        Map<String, Object> map = new HashMap<>();

        // 同步查询
        Spider spider = Spider.create(new PlayMovieUrlProcessor());
        ResultItems result = spider.get(collectionHref);
        if (result != null) {
            WebMovieVO webMovieVO = result.get("webMovie");
            map.put("code", 200);
            map.put("movie", webMovieVO);
            return map;
        }

        return map;
    }

    @Override
    public Map<String, Object> searchUserMovie(Long userId, Integer pageIndex, Integer pageSize) {
        Map<String, Object> map = new HashMap<>();

        IPage<UserHistoryMovieVO> page = userHistoryService.pageHistory(new Page<MovieUserHistoryEntity>(pageIndex, pageSize), userId);

        map.put("code", 200);
        map.put("pages", page);

        return map;
    }

    @Override
    public Map<String, Object> searchByUserHistoryId(Long userId, Long userHistoryId) {
        Map<String, Object> map = new HashMap<>();

        MoviePlayerInfoVO moviePlayerInfoVO = userHistoryService.selectByUserHistoryId(userId, userHistoryId);

        map.put("code", 200);
        map.put("info", moviePlayerInfoVO);

        return map;
    }

    @Override
    public Map<String, Object> updateUserHistoryPlayer(Long userId, MoviePlayerInfoVO info) {
        Map<String, Object> map = new HashMap<>();

        MovieJiListEntity jiList = jiListService.getOne(new QueryWrapper<MovieJiListEntity>().eq("movie_ji_url", info.getMovieJiUrl()));
        if (jiList == null) {
            logger.error("user back or quit is error! the movie url is {}", info.getMovieJiUrl());
            map.put("code", -1);
            map.put("msg", "update movie is error!");
            return map;
        }
        MovieUserHistoryEntity userHistory = userHistoryService.getOne(new QueryWrapper<MovieUserHistoryEntity>().eq("user_id", userId).eq("movie_id", jiList.getMovieId()));
        userHistory.setMovieNowJi(jiList.getId());
        userHistory.setMovieNowSecond(info.getMovieNowSecond().toString());
        userHistory.setUpdateTime(new Date());
        userHistoryService.updateById(userHistory);
        map.put("code", 200);
        map.put("msg", "user back or quit update movie is success!");

        return map;
    }

    @Override
    public Map<String, Object> removeUserMovie(Long userId, UserHistoryMovieVO info) {
        Map<String, Object> map = new HashMap<>();

        userHistoryService.getBaseMapper().deleteById(info.getUserHistoryId());
        map.put("code", 200);
        map.put("msg", "remove movie success!");

        return map;
    }

    @Override
    public Map<String, Object> searchMovieInfo(String detailUrl) {
        Map<String, Object> map = new HashMap<>();

        // 同步查询
        Spider spider = Spider.create(new SearchMovieDetailProcessor());
        ResultItems result = spider.get(detailUrl);
        if (result != null) {
            List<SearchMovieDetailVO> movieDetailList = result.get("list");
            map.put("code", 200);
            map.put("list", movieDetailList);
            return map;
        }

        return map;
    }

    /**
     * 保存视频信息
     * @param userId 用户ID
     * @param movieVO 影视信息
     * @param movie80SJiShuVOS 影视集数信息
     */
//    @Transactional(rollbackFor = Exception.class)
    public void saveMovie(Long userId, Search80SMovieVO movieVO, List<Movie80SJiShuVO> movie80SJiShuVOS) {
        String movieType = CommonUtils.getMovieType(movieVO.getMovieHref());
        String movieWebId = CommonUtils.getMovieWebId(movieVO.getMovieHref());
        MovieListEntity movieList = movieListService.getOne(new QueryWrapper<MovieListEntity>().eq("movie_web_id", movieWebId));
        if (movieList == null) {
            // 保存
            movieList = new MovieListEntity();
            movieList.setMovieName(movieVO.getMovieName());
            movieList.setMovieWebHref(movieVO.getMovieHref());
            movieList.setMovieTotalEpisodes(0);
            movieList.setMovieImgHref(movieVO.getImgHref());
            movieList.setMovieNowEpisodes(0);
            // 是否已完结
            String movieUpdate = movieVO.getMovieUpdate();
            if (StringUtils.isNotEmpty(movieUpdate)) {
                // 去掉多余的空格
                movieUpdate = movieUpdate.replaceAll(" ", "");
                if (movieUpdate.equals("已完结")) {
                    movieList.setMovieIsEnd(0);
                } else {
                    movieList.setMovieIsEnd(1);
                    String jiNum = movieUpdate.replace("更新至第", "").replace("集", "");
                    movieList.setMovieNowEpisodes(Integer.valueOf(jiNum));
                }
            }
            movieList.setMovieWebId(movieWebId);
            movieList.setMovieType(getMovieType(movieType));
            Date date = new Date();
            movieList.setCreateTime(date);
            movieList.setUpdateTime(date);
            movieListService.save(movieList);
        }
        if (!CollectionUtils.isEmpty(movie80SJiShuVOS)) {
            int count = jiListService.count(new QueryWrapper<MovieJiListEntity>().eq("movie_id", movieList.getId()));
            if (count <= 0) {
                // 保存
                List<MovieJiListEntity> jiList = new ArrayList<>();
                for (Movie80SJiShuVO movie80SJiShuVO : movie80SJiShuVOS) {
                    MovieJiListEntity jiListEntity = new MovieJiListEntity();
                    jiListEntity.setMovieId(movieList.getId());
                    jiListEntity.setPlayName(movie80SJiShuVO.getPlayName());
                    jiListEntity.setMovieJiUrl(movie80SJiShuVO.getPlayUrl());
                    Date date = new Date();
                    jiListEntity.setCreateTime(date);
                    jiListEntity.setUpdateTime(date);
                    jiList.add(jiListEntity);
                }
                jiListService.saveBatch(jiList);
            } else {
                // 添加没有的
                if (movie80SJiShuVOS.size() > count) {
                    int num = movie80SJiShuVOS.size() - count;
                    List<MovieJiListEntity> jiList = new ArrayList<>();
                    for (int i=0;i<num;i++) {
                        MovieJiListEntity jiListEntity = new MovieJiListEntity();
                        jiListEntity.setMovieId(movieList.getId());
                        jiListEntity.setPlayName(movie80SJiShuVOS.get(i).getPlayName());
                        jiListEntity.setMovieJiUrl(movie80SJiShuVOS.get(i).getPlayUrl());
                        Date date = new Date();
                        jiListEntity.setCreateTime(date);
                        jiListEntity.setUpdateTime(date);
                        jiList.add(jiListEntity);
                    }
                    jiListService.saveBatch(jiList);
                }
            }
        }
        // 添加用户播放历史记录
        MovieUserHistoryEntity userHistory = userHistoryService.getOne(new QueryWrapper<MovieUserHistoryEntity>().eq("movie_id", movieList.getId()).eq("user_id", userId));
        if (userHistory == null) {
            userHistory = new MovieUserHistoryEntity();
            userHistory.setMovieId(movieList.getId());
            userHistory.setUserId(userId);
            Date date = new Date();
            userHistory.setCreateTime(date);
            userHistory.setUpdateTime(date);
            userHistoryService.save(userHistory);
        }
    }

    private Integer getMovieType(String type) {
        switch (type) {
            case "ju" -> {
                return 0;
            }
            case "movie" -> {
                return 1;
            }
            case "dw" -> {
                return 2;
            }
            case "zy" -> {
                return 3;
            }
            default -> {
                return 4;
            }
        }
    }
}
